package Renderer;
import java.util.ArrayList;
public class RTree {
/**
* @uml.property name="rootNode"
* @uml.associationEnd multiplicity="(1 1)"
*/
RTree_node rootNode;
public RTree() {
rootNode = new RTree_node();
}
// ==============================================================================
// R-TREE ROUTINES
// ==============================================================================
public RTree(ArrayList<Vertex> vertices, int vertex_count) {
index_vertices(vertices, vertex_count);
}
// This routine builds an R-tree node containing ptrs to all vertices within
// begin/end. Begin/end
// will be sorted multiple times as needed to accomplish this. "depth" is
// the level on the tree -
// we use this to resort the vertices. When called with a depth of 0 (first
// call) it is expected
// that the vertices are sorted by X coordinate already.
// We return a node ptr with the lsb set or cleared depending on whether we
// made an internal or
// leaf node.
public RTree_node index_vertices_recursive(ArrayList<Vertex> vertices, int begin,
int end, int depth) {
int i;
int count = 0;
if (end >= begin)
count = end - begin;
if (count <= RTree_leaf.LEAF_DIM) {
// Leaf node case: we have so few nodes, we can fit them into a
// single leaf.
// / Build the leaf node, compute the bounding box, and return the
// node with
// its LSB set.
RTree_leaf leaf = new RTree_leaf();
float[] minBounds = leaf.getMinBounds();
float[] maxBounds = leaf.getMaxBounds();
float[] location = vertices.get(begin).getLocation();
minBounds[0] = maxBounds[0] = location[0];
minBounds[1] = maxBounds[1] = location[1];
minBounds[2] = maxBounds[2] = location[2];
leaf.setCount(count);
for (i = 0; i < count; ++i, begin++) {
location = vertices.get(begin).getLocation();
minBounds[0] = Math.min(minBounds[0], location[0]);
maxBounds[0] = Math.max(maxBounds[0], location[0]);
minBounds[1] = Math.min(minBounds[1], location[1]);
maxBounds[1] = Math.max(maxBounds[1], location[1]);
minBounds[2] = Math.min(minBounds[2], location[2]);
maxBounds[2] = Math.max(maxBounds[2], location[2]);
leaf.setVertex(i, vertices.get(begin));
}
return (RTree_node) leaf;
} else {
// Intermediate node case. We will sort the nodes by X, Y, or Z
// depending
// on the axis - by changing the axis we naturally isolate vertices
// in N dimensions.
// Optimization: avoid one full sort of all vertices since we know
// our source
// input is passed in in X-sorted order!
if (depth > 0)
MeshSmooth.quickSort_n(vertices, begin, count-1, depth % 3);
int split = count / 2;
// Now recurse on each half of the vertices to get our two child
// nodes.
RTree_node left = index_vertices_recursive(vertices, begin, begin+split,
depth + 1);
RTree_node right = index_vertices_recursive(vertices, begin+split, end,
depth + 1);
// Build our node around our two child nodes; our bounds are the
// union of our
// child bounds. (We don't want to re-check the bounds of all of our
// vertices.)
RTree_node n = new RTree_node();
n.setLeft(left);
n.setRight(right);
// todo
// left = GET_CLEAN(left);
// right = GET_CLEAN(right);
float minBounds[] = new float[3];
float maxBounds[] = new float[3];
float minBounds_left[] = left.getMinBounds();
float minBounds_right[] = right.getMinBounds();
float maxBounds_left[] = left.getMaxBounds();
float maxBounds_right[] = right.getMaxBounds();
for (i = 0; i < 3; ++i) {
minBounds[i] = Math.min(minBounds_left[i], minBounds_right[i]);
maxBounds[i] = Math.max(maxBounds_left[i], maxBounds_right[i]);
}
n.setMinBounds(minBounds);
n.setMaxBounds(maxBounds);
return n;
}
}
// Top-level call to index nodes. Returns the root node of our r-tree. See
// note below about not indexing co-colocated nodes!!
public RTree_node index_vertices(ArrayList<Vertex> vertices, int count) {
int i;
ArrayList<Vertex> arr = new ArrayList<Vertex>(count);
RTree_node return_node;
// We only R-tree the FIRST of a RANGE of points that are mathematically
// equal.
// Code doing the query can re-construct the rest of the range by
// walking forward.
// This cuts our R-tree down a LOT - in the case of the 48x48 baseplate
// as a whole,
// this cuts vertex count by 80% (!). Since the R-tree build is
// O(NlogNlogN) - that
// is, THE most time-complexity-expensive operation in the algo, this is
// sort of a big deal.
int index = 0;
for (i = 0; i < count; ++i) {
if (i == 0
|| MeshSmooth.compare_points(vertices.get(i - 1).getLocation(),
0, vertices.get(i).getLocation(), 0) != 0) {
arr.add(vertices.get(i));
index++;
}
}
return_node = index_vertices_recursive(arr, 0, index, 0);
this.rootNode = return_node;
return return_node;
}
// Utility: Returns true if two 3-d AABBs (stored as min XYZ and max XYZ)
// overlap, including
// overlaps of their edges.
public static int overlap(float b1_min[], float b1_max[], float b2_min[],
float b2_max[]) {
if (b1_min[0] > b2_max[0])
return 0;
if (b2_min[0] > b1_max[0])
return 0;
if (b1_min[1] > b2_max[1])
return 0;
if (b2_min[1] > b1_max[1])
return 0;
if (b1_min[2] > b2_max[2])
return 0;
if (b2_min[2] > b1_max[2])
return 0;
return 1;
}
// Returns true if a point is inside an AABB, or on its edges.
public static int inside(float b1_min[], float b1_max[], float p[]) {
if (p[0] >= b1_min[0] && p[0] <= b1_max[0])
if (p[1] >= b1_min[1] && p[1] <= b1_max[1])
if (p[2] >= b1_min[2] && p[2] <= b1_max[2])
return 1;
return 0;
}
// todo
// R-tree scanning routine. A functor "visitor" is called (with "ref" passed
// each time) for every vertex in the Rtree "N" whose bounds
// are within (inclusive of edges) min_bounds -> max_bounds.
// public void scan_rtree(RTree_node n, float min_bounds[3], float
// max_bounds[3], void (* visitor)(Vertexv, void * ref), void * ref)
// {
// if(IS_LEAF(n))
// {
// struct RTree_leaf * l = (GET_LEAF(n));
// if(overlap(minBounds,maxBounds,min_bounds,max_bounds))
// {
// int i;
// for(i = 0; i < l->count; ++i)
// if(inside(min_bounds,max_bounds,l->vertices[i].getLocation()))
// {
// visitor(l->vertices[i], ref);
// }
// }
// }
// else
// {
// if(overlap(n->min_bounds,n->max_bounds,min_bounds,max_bounds))
// {
// scan_rtree(n->left, min_bounds,max_bounds, visitor, ref);
// scan_rtree(n->right, min_bounds,max_bounds, visitor, ref);
// }
// }
// }
// }
// ==============================================================================
// R-TREE DATASTRUCTURES
// ==============================================================================
// http://en.wikipedia.org/wiki/R-tree
//
// Our R-tree stores vertices by their 3-d AABBs; for internal nodes, we
// store a
// pair of child nodes; for leaf nodes we store up to 8 individual vertices.
// Because the R-tree has diminishing returns as we get to a small scale, it
// makes
// sense to store more than one triangle per leaf - it cuts down nodes and
// gets
// us
// better memory access patterns.
//
// We set the LSB of our pointers to 1 for leaf nodes as a way to indicate
// the
// type of the node in its parent.
}
class RTree_node {
/**
* @uml.property name="min_bounds" multiplicity="(0 -1)" dimension="1"
*/
float min_bounds[];
/**
* @uml.property name="max_bounds" multiplicity="(0 -1)" dimension="1"
*/
float max_bounds[];
/**
* @uml.property name="left"
* @uml.associationEnd inverse="right:Renderer.RTree_node"
*/
RTree_node left;
/**
* @uml.property name="right"
* @uml.associationEnd inverse="left:Renderer.RTree_node"
*/
RTree_node right;
/**
* @uml.property name="leaf"
* @uml.associationEnd
*/
RTree_leaf leaf = null;
public RTree_node() {
min_bounds = new float[3];
max_bounds = new float[3];
left = null;
right = null;
}
public void setMaxBounds(float[] maxBounds) {
for (int i = 0; i < 3; i++)
max_bounds[i] = maxBounds[i];
}
public void setMinBounds(float[] minBounds) {
for (int i = 0; i < 3; i++)
min_bounds[i] = minBounds[i];
}
public float[] getMaxBounds() {
return max_bounds;
}
public float[] getMinBounds() {
return min_bounds;
}
/**
* @param right
* @uml.property name="right"
*/
public void setRight(RTree_node right) {
this.right = right;
}
/**
* @param left
* @uml.property name="left"
*/
public void setLeft(RTree_node left) {
this.left = left;
}
}
class RTree_leaf extends RTree_node {
public static final int LEAF_DIM = 8;
/**
* @uml.property name="count"
*/
int count; // Number of actual vertices, might be less than
/**
* @uml.property name="vertices"
* @uml.associationEnd multiplicity="(0 -1)"
*/
Vertex // leaf DIM.
vertices[];
public RTree_leaf() {
super();
vertices = new Vertex[LEAF_DIM];
}
public void setVertex(int i, Vertex vertex) {
vertices[i] = vertex;
}
/**
* @param count
* @uml.property name="count"
*/
public void setCount(int count) {
this.count = count;
}
public float[] getMinBounds() {
return this.min_bounds;
}
public float[] getMaxBounds() {
return this.max_bounds;
}
/**
* @return
* @uml.property name="count"
*/
public int getCount() {
return count;
}
/**
* @return
* @uml.property name="vertices"
*/
public Vertex[] getVertices() {
return vertices;
}
}